import { readBody, defineEventHandler } from 'h3'
import { recordLog } from '../util/log'

// POST /api/proxy
// body: { url: string, method?: string, headers?: Record<string,string>, body?: string|object, timeoutSec?: number }
export default defineEventHandler(async (event) => {
  try {
    const payload = await readBody(event) as any
    const url = payload?.url
    if (!url || typeof url !== 'string' || !/^https?:\/\//i.test(url)) {
      event.node.res.statusCode = 400
      return { status: 400, message: 'invalid url' }
    }

    const method = (payload.method || 'GET').toUpperCase()
    const headers = Object.assign({}, payload.headers || {})

    // Remove some hop-by-hop headers that shouldn't be forwarded
    const hopByHop = ['host','connection','keep-alive','proxy-authenticate','proxy-authorization','te','trailers','transfer-encoding','upgrade']
    for (const h of hopByHop) delete headers[h]

    const fetchOpts: any = { method, headers }

    if (method !== 'GET' && method !== 'HEAD') {
      if (typeof payload.body === 'string') fetchOpts.body = payload.body
      else if (payload.body === undefined || payload.body === null) fetchOpts.body = undefined
      else fetchOpts.body = JSON.stringify(payload.body)
      // If we serialized an object body and Content-Type not set, set to application/json
      if (!Object.keys(headers).some(k => k.toLowerCase() === 'content-type') && typeof payload.body !== 'string') {
        fetchOpts.headers = Object.assign({}, fetchOpts.headers, { 'Content-Type': 'application/json' })
      }
    }

    const timeoutMs = Number(payload.timeoutSec ? payload.timeoutSec * 1000 : (payload.timeoutMs || 30000))
    const ac = new AbortController()
    const to = setTimeout(() => ac.abort(), Math.max(1000, timeoutMs))
    fetchOpts.signal = ac.signal

    const resp = await fetch(url, fetchOpts)
    clearTimeout(to)

    const text = await resp.text()
    const rh: Record<string,string> = {}
    resp.headers.forEach((v,k) => { rh[k] = v })

    // Return a JSON wrapper so front-end can read status/headers/body without CORS issues
    return {
      status: resp.status,
      statusText: resp.statusText,
      headers: rh,
      body: text
    }
  } catch (err: any) {
    try { await recordLog(event as any, { message: `proxy error ${String(err)}`, userId: 0 }) } catch (e) { /* ignore */ }
    event.node.res.statusCode = 500
    return { status: 500, message: 'proxy error', error: String(err) }
  }
})
